# -*- coding: utf-8 -*-
"""
Created on Mon Dec  1 14:55:44 2014

@author: wei
"""

from flask import Blueprint,render_template, flash, redirect, session, url_for, \
    request, g, abort,Response
from flask.ext.login import login_user, logout_user, current_user, login_required
from app import app,db,forms
from app.models import *
import json
import os
import config as cfg
import shutil
import glob
import deploy
import re
import eventlet
import html

@app.route('/login', methods = ['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect('/')
    form=forms.LoginForm()
    if form.validate_on_submit():
    #if request.method=='POST' and form.validate():
        user=Users.query.filter_by(username=form.username.data).first()
        if user:
            if user.check_pwd(form.password.data):
                if login_user(user,remember=form.remember_me.data):
                    return redirect(request.args.get("next") or "/")
                else:
                   flash('用户状态不可用!')
            else:
                flash('密码错误!')
        else:
            flash('用户不存在!')
    else:
        err=form.get_last_error()
        if err:
            flash(err)
    return render_template('login.html', form=form)

@app.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(url_for('login'))

@app.route("/modify_pwd", methods = ['POST'])
@login_required
def modify_pwd():
    old_pwd=request.form.get('old_pwd','')
    new_pwd=request.form.get('new_pwd','')
    if g.user.set_pwd(old_pwd,new_pwd):
        db.session.add(g.user)
        db.session.commit()
        return '1'
    return ''

@app.route('/')
@app.route('/svn_repository')
@login_required
def svn_repository():
    return render_template('svn_repository.html')

@app.route('/edit_repository',methods=['GET','POST'])
@app.route('/edit_repository/<int:id>',methods=['GET','POST'])
@login_required
def edit_repository(id=None):#增加/编辑仓库
    if id:
        repos=Repository.query.get(id)
    else:
        repos=Repository()
    form=forms.RepositoryForm(request.form,repos)
    if request.method=='POST':
        if not form.validate():
            return form.get_last_error()
          
        form.populate_obj(repos)
        db.session.add(repos)
        db.session.commit()
        return '1'

    return render_template("form_repository.html", form=form,curr_id=id)


_cfg_def_list={'SVN_CFG_FILE_AUTHZ':'authz',
              'SVN_CFG_FILE_PASSWD':'passwd'}
                 
@app.route('/svn_config',methods=['GET','POST'])
@login_required
def svn_config():
    cfg        =request.args.get('cfg')
    restart    =request.args.get('restart')
    cfg_content=request.form.get('cfg_content','')
    
    if cfg:#编辑配置
        cfg_file=Configs.get_value(cfg,cache_timeout=0)
        if not cfg_file:
            db.session.commit()#get_value里没有配置时会自动增加,但没提交,这里提交一下
            flash('请先在[系统设置]里设置%s,即svn配置文件%s的全路径!' % (cfg,_cfg_def_list[cfg]))
        elif not os.path.exists(cfg_file):
            flash('系统配置[%s]指向的配置文件[%s]不存在!' % (cfg,cfg_file))
        else:
            if request.method=='POST':
                with open(cfg_file,'w') as f:
                    f.write(cfg_content)
            else:
                with open(cfg_file,'r') as f:
                    cfg_content=f.read()
    elif restart:#重启
        restart_shell_file=Configs.get_value('SVN_RESTART_SHELL',cache_timeout=0)
        if not restart_shell_file:
            db.session.commit()
            flash('请先在[系统设置]里设置SVN_RESTART_SHELL,指向重启svn的shell文件!')
        elif not os.path.exists(restart_shell_file):
            flash('SVN重启shell文件[%s]不存在!' % restart_shell_file)
        else:
            cmd='echo "执行SVN重启脚本:{0}"\nbash {0}'.format(restart_shell_file)  
            f=os.popen(cmd)
            cfg_content=f.read()
            f.close()
            
    return render_template('svn_config.html',
                            cfg_def_list=_cfg_def_list,
                            curr_cfg=cfg,
                            cfg_content=cfg_content)
    
@app.route('/del_repository/<int:id>',methods=['POST'])
@login_required
def del_repository(id):#删除仓库
    r=Repository.query.get_or_404(id)
    db.session.delete(r)
    db.session.commit()
    return '1'


@app.route('/qry_repository_data',methods=['GET','POST'])
@login_required
def qry_repository_data():#查询仓库
    page    =int(request.form.get('page',1))
    rows_num=int(request.form.get('rows',20))
    
    q=Repository.query
    result={}
    p=q.paginate(page,rows_num)
    result['total']=p.total
    result['rows']=[r.as_dict('id','name','remark') for r in p.items]
    return json.dumps(result)

@app.route('/deploy_repository/<int:id>')
@login_required
def deploy_repository(id):#部署管理
    return render_template('deploy_repository.html',repos_id=id)

@app.route('/qry_deploy_data/<int:repos_id>',methods=['GET','POST'])
@login_required
def qry_deploy_data(repos_id):#查询部署记录
    page    =int(request.form.get('page',1))
    rows_num=int(request.form.get('rows',20))

    r=Repository.query.get_or_404(repos_id)
    q=r.deploy_infos
    result={}
    p=q.paginate(page,rows_num)
    result['total']=p.total
    result['rows']=[r.as_dict('id','branch','deploy_servers','deploy_path','deploy_status',
                    deploy_path=html.escape) for r in p.items]
    return json.dumps(result)

@app.route('/edit_deploy/<int:repos_id>',methods=['GET','POST'])
@app.route('/edit_deploy/<int:repos_id>/<int:id>',methods=['GET','POST'])
@login_required
def edit_deploy(repos_id,id=None):#增加/编辑部署
    if id:
        rec=Deploy_info.query.get(id)
    else:
        rec=Deploy_info(server_ids='')
        
    branch        =request.values.get('branch'        ,rec.branch)
    deploy_servers=request.values.get('deploy_servers',rec.server_ids)
    deploy_path   =request.values.get('deploy_path'   ,rec.deploy_path)
    init_cmds     =request.values.get('init_cmds'     ,rec.init_cmds)
    cmds          =request.values.get('cmds'          ,rec.cmds)
    
    form=forms.DeployForm(request.form,branch=branch,deploy_servers=deploy_servers.split(','),
                          deploy_path=deploy_path,init_cmds=init_cmds,cmds=cmds)
    form.deploy_servers.choices=[(str(id),'%s--%s' % (host,rm)) for id,host,rm in\
                                 Servers.query.with_entities(Servers.id,Servers.host,Servers.remark)]
    if request.method=='POST':
        if not form.validate():
            return form.get_last_error()
        
        rec.repository_id=repos_id
        rec.branch     =form.branch.data
        rec.server_ids =','.join(form.deploy_servers.data)
        rec.deploy_path=form.deploy_path.data
        rec.init_cmds  =form.init_cmds.data
        rec.cmds       =form.cmds.data
        db.session.add(rec)
        db.session.commit()
        
        return '1'

    return render_template("form_deploy.html", form=form,repos_id=repos_id,id=id)

@app.route('/del_deploy/<int:id>',methods=['POST'])
@login_required
def del_deploy(id):#删除部署
    r=Deploy_info.query.get_or_404(id)
    db.session.delete(r)
    db.session.commit()
    return '1'
    
@app.route('/server')
@login_required
def server():
    return render_template('server.html')

@app.route('/qry_server_data',methods=['GET','POST'])
@login_required
def qry_server_data():
    page    =int(request.form.get('page',1))
    rows_num=int(request.form.get('rows',20))
    
    q=Servers.query
    result={}
    p=q.paginate(page,rows_num)
    result['total']=p.total
    result['rows']=[r.as_dict('id','host','port','user','remark') for r in p.items]
    return json.dumps(result)
 
@app.route('/edit_server',methods=['GET','POST'])
@app.route('/edit_server/<int:id>',methods=['GET','POST'])
@login_required
def edit_server(id=None):#新增/编辑服务器
    if id:
        server=Servers.query.get(id)
    else:
        server=Servers()
    form=forms.ServerForm(request.form,server)
    if request.method=='POST':
        if not form.validate():
            return form.get_last_error()
            
        form.populate_obj(server)
        db.session.add(server)
        db.session.commit()
        return '1'

    return render_template("form_server.html", form=form,curr_id=id)

@app.route('/del_server/<int:id>',methods=['POST'])
@login_required
def del_server(id):#删除服务器
    r=Servers.query.get_or_404(id)
    db.session.delete(r)
    db.session.commit()
    return '1'
     
@app.route('/sys_config')
@login_required
def sys_config():
    return render_template('sys_config.html')

@app.route('/qry_config_data',methods=['POST'])
@login_required
def qry_config_data():#查询系统设置数据
    page    =int(request.form.get('page',1))
    rows_num=int(request.form.get('rows',20))

    q =Configs.query
    
    result={}
    rows=[]
    result['total']=q.count()
    for config in q.paginate(page,rows_num,True).items:
        rows.append(config.as_dict("id","key","value","descript","num"))
    result['rows']=rows
   
    return json.dumps(result)

@app.route('/edit_cfg',methods=['GET','POST'])
@app.route('/edit_cfg/<int:id>',methods=['GET','POST'])
@login_required
def edit_cfg(id=None):#新增编辑设置
    if id:
        config=Configs.query.get(id)
    else:
        config=Configs()
    form =forms.Config_Form(request.form,config)
    if request.method=='POST':#
        if not form.validate():
            return form.get_last_error()
        form.populate_obj(config)
        db.session.add(config)
        db.session.commit()
        return '1'
    return render_template('form_edit_cfg.html',form=form,id=id)
    
@app.route('/del_cfg/<int:cid>',methods=['GET','POST'])
@login_required
def del_cfg(cid):
    Configs.query.filter_by(id=cid).delete()
    db.session.commit()
    return '1'
    
@app.route('/set_hook/<int:id>',methods=['GET','POST'])
@login_required
def set_hook(id):#设置SVN HOOK
    src_hook_file=os.path.join(cfg.basedir,'post-commit.temp')
    if not os.path.exists(src_hook_file):
        return 'post-commit模板文件[%s]不存在!' % src_hook_file
    repos=Repository.query.get_or_404(id)
    target_hook_file=os.path.join(repos.location,'hooks/post-commit')
    try:
        shutil.copyfile(src_hook_file,target_hook_file)
        #设置权限
        chmod='chmod a+x %s' % target_hook_file
        os.system(chmod)
        
        return '1'
    except Exception as e:
        return str(e)
     
@app.route('/sys_users')
@login_required   
def sys_users():
    return render_template('sys_users.html')
   
@app.route('/qry_user_data',methods=['POST'])
@login_required   
def qry_user_data():
    page    =int(request.form.get('page',1))
    rows_num=int(request.form.get('rows',20))

    q =Users.query
    
    result={}
    result['total']=q.count()
    result['rows']=[r.as_dict('id','username','remarkname',
        'status','email','is_admin','created_date')\
         for r in q.paginate(page,rows_num).items]
    print(result)
    return json.dumps(result)
    
@app.route('/edit_user',methods=['GET','POST'])
@login_required   
def edit_user():
    if not g.user.is_admin:
        return '<h3>不是管理员,没权限操作!</h3>'
        
    user_id=request.values.get('uid')
    if user_id:
        user=Users.query.get(user_id)
    else:
        user=Users()

    form =forms.Users_Form(request.form,user)
    if request.method=='POST':
        if user_id:#编辑
            user.remarkname=form.remarkname.data
        else:#新增
            if not form.validate():
                return form.get_last_error()
            m =db.session.query(Users.query.filter_by(username=user.username).exists()).scalar()
            if m ==True:
                return "用户名已存在！"
            n=db.session.query(Users.query.filter_by(email=user.email).exists()).scalar()
            if n ==True:
                return "该邮箱已注册！"

            form.populate_obj(user)

        try:
            db.session.add(user)
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            return str(e)

        return '1'
        
    return render_template('form_user.html',form=form,
                           curr_user_id=user_id,
                           is_edit=bool(user_id))

@app.route('/update_user_status/<int:uid>/<int:stat>',methods=['GET','POST'])
@login_required  
def update_user_status(uid,stat):
    if not g.user.is_admin:
        return '没有权限操作!'
        
    user=Users.query.get(uid)
    if not user:
        return '用户不存在(id=%d)!' % uid
        
    user.status='STA_ACTIVE' if stat==1 else 'STA_DISACTIVE'
    db.session.add(user)
    db.session.commit()
    
    return '1'
    
@app.route('/logs')
@login_required
def logs():#日志列表
    log_path=os.path.join(cfg.basedir,'logs')
    
    if os.path.exists(log_path):
        file_list=sorted(glob.glob('%s/*.*' % log_path), key=os.path.getmtime, reverse=True)

    return render_template('logs.html',log_list=map(os.path.basename,file_list))
    
@app.route('/view_log/<string:logname>')
@login_required
def view_log(logname):#显示日志
    log_full_name=os.path.join(cfg.basedir,'logs',logname)

    if os.path.exists(log_full_name):
        rsp=Response(mimetype='text/plain')
        with open(log_full_name,'r') as f:
            rsp.stream.writelines(f.readlines())
        return rsp
        
    return '日志文件[%s]不存在!' % logname


def _do_thread_deploy(dinfo):
    try:
        deploy.logger.info('***********************************************')
        deploy.logger.info('手动发布[%s]...' % os.path.join(dinfo.repository_name,dinfo.branch))
        deploy.deploy_branch(dinfo,eventlet.sleep)
    except Exception as e:
        deploy.logger.error('手动发布出错:%s' % str(e))
        
    
@app.route('/do_deploy/<int:id>',methods=['POST'])
@login_required
def do_deploy(id):#手动发布分枝
    dinfo=Deploy_info.query.get(id)
    if not dinfo:
        return '分枝不存在!'
     
    #重新加载日志对象,不然跨天会和自动发布有冲突
    deploy.reload_logger()
    
    eventlet.spawn_n(_do_thread_deploy,dinfo.as_dict('id','server_ids','repository_name',
                                                     'branch','deploy_path','init_cmds','cmds'))

    return '1'


@app.route('/server_shell')
@login_required
def server_shell():
    sid=request.args.get('id')
    
    gateone_url=Configs.get_value('GATEONE_URL')
    if not gateone_url:
        return '未设置GATEONE_URL!'
    
    server=Servers.query.get_or_404(sid)
    shell_url='%s/?location=%s&ssh=ssh://%s@%s:%d' % (gateone_url.rstrip('/'),\
        server.host.replace('.','_'),server.user,server.host,server.port)
    
    return redirect(shell_url)
